home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-02-01 | 20.6 KB | 466 lines | [TEXT/CCL2] |
- ;-*- Mode: Lisp; Package: CCL -*-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; edit-definition-patch.lisp
- ;;copyright © 1992, 1993, Apple Computer, Inc.
- ;;
- ;;
- ;; Make edit-definition (meta-.) on a method with specializers
- ;; find all the applicaple methods sorted by applicability
- ;;
- ;;
- ; Notes:
- ; :primary in qualifier position means just primary
- ; no qualifier means all
- ; Also includes patch to edit-definition-spec-lessp for edit-callers
- ; make dialog do the same as meta-.
-
- ;10/27/92 fix edit-definition-p when given a method-function
- ; 06/22/92 clean up a bit, make error report less verbose and clearer
- ; 06/17/92 fix definition-spec-lessp for (setf ..), show which are setf when both
-
- (in-package :ccl)
-
- (defvar *ed-show-setf* nil)
-
- (let ((*warn-if-redefine* nil)
- (*warn-if-redefine-kernel* nil))
-
- ; modified version of %compute-applicable-methods*
- ; omit errors and args are class names not instances
- (defun find-applicable-methods (name args qualifiers)
- (let ((gf (fboundp name)))
- (when (and gf (typep gf 'standard-generic-function))
- (let* ((methods (%gf-methods gf))
- (args-length (length args))
- (bits (lfun-bits gf))
- arg-count res)
- (when methods
- (setq arg-count (length (%method-specializers (car methods))))
- (unless (or (logbitp $lfbits-rest-bit bits)
- (logbitp $lfbits-keys-bit bits)
- (<= args-length
- (+ (ldb $lfbits-numreq bits) (ldb $lfbits-numopt bits))))
- (return-from find-applicable-methods))
- (let ((cpls (make-list arg-count)))
- (declare (dynamic-extent cpls))
- (do ((args-tail args (cdr args-tail))
- (cpls-tail cpls (cdr cpls-tail)))
- ((null cpls-tail))
- (let ((arg (car args-tail)) thing)
- (if (consp arg)
- (setq thing (class-of (cadr arg)))
- (setq thing (find-class (or arg t))))
- (setf (car cpls-tail)
- (%class-precedence-list thing))))
- (dolist (m methods)
- (if
- (and (or (eq qualifiers t)
- (equal qualifiers (%method-qualifiers m)))
- (%my-method-applicable-p m args cpls))
- (push m res)))
- (let ((methods (sort-methods res cpls (%gf-precedence-list gf))))
- (if (eq (ccl::generic-function-method-combination gf)
- ccl::*standard-method-combination*)
- (let (arounds befores primaries afters)
- (dolist (method methods)
- (case (car (method-qualifiers method))
- (:before (push method befores))
- (:after (push method afters))
- (:around (push method arounds))
- (t (push method primaries))))
- (nconc (nreverse arounds)
- (nreverse befores)
- (nreverse primaries)
- afters))
- methods))))))))
-
- ; modified version of %method-applicable-p - args are class names not instances
- (defun %my-method-applicable-p (method args cpls)
- (do ((specs (%method-specializers method) (cdr specs))
- (args args (cdr args))
- (cpls cpls (cdr cpls)))
- ((null specs) t)
- (let ((spec (car specs)))
- (if (listp spec)
- (unless (equal (car args) spec)
- (return nil))
- (unless (or (eq (caar cpls) (find-class t))
- (memq spec (car cpls)))
- (return nil))))))
-
- (defun parse-definition-spec (form)
- (let ((type t)
- name classes qualifiers)
- (cond
- ((consp form)
- (cond ((eq (car form) 'setf)
- (setq name form))
- (t (setq name (car form))
- (let ((last (car (last (cdr form)))))
- (cond ((and (listp last)(or (null last)(neq (car last) 'eql)))
- (setq classes last)
- (setq qualifiers (butlast (cdr form))))
- (t (setq classes (cdr form)))))
- (cond ((null qualifiers)
- (setq qualifiers t))
- ((equal qualifiers '(:primary))
- (setq qualifiers nil))))))
- (t (setq name form)))
- (when (and (consp name)(eq (car name) 'setf))
- (setq name (or (%setf-method (cadr name)) name))) ; e.g. rplacd
- (when (consp qualifiers)
- (mapc #'(lambda (q)
- (when (listp q)
- (return-from parse-definition-spec)))
- qualifiers))
- (when classes
- (mapc #'(lambda (c)
- (when (not (and c (or (symbolp c)(and (consp c)(eq (car c) 'eql)))))
- (return-from parse-definition-spec)))
- classes))
- (when (or (consp classes)(consp qualifiers))(setq type 'method))
- (values type name classes qualifiers)))
-
-
-
- (defmethod ed-edit-definition ((w fred-mixin) &optional pos)
- (let ((form (ignore-errors (ed-current-sexp w pos))))
- (cond
- ((null form)
- (edit-definition-dialog))
- (t (edit-definition-spec form)))))
-
- (defun edit-definition-spec (form)
- (multiple-value-bind (pos files name type classes qualifiers)
- (edit-definition form)
- (cond (name
- (when (and (not pos)(not files))
- ; if no source file info - search all buffers?
- (dolist (ww (windows))
- (when (and
- (typep ww 'fred-window)
- (not (typep ww 'listener)))
- (setq pos (search-for-def (fred-buffer ww) name type classes qualifiers))
- (when pos
- (window-select ww)
- (ed-push-mark ww)
- (window-scroll ww pos)
- (return))))
- (when (not pos)
- (edit-definition-error name classes qualifiers nil))))
- (t (let ((*print-length* 3)(*print-level* 2))
- (ed-beep)
- (format t "~S not understood by edit definition." form))))))
-
- (defun edit-definition-error (name classes qualifiers file)
- (ed-beep)
- (when (eq t qualifiers)(setq qualifiers nil))
- (let ((*print-length* 3)(*print-level* 2))
- (if file
- (format t "Can't find ~s~@[ with specializers ~s~]~@[ qualifers ~s~] in file ~s."
- name classes qualifiers file)
- (format t "There is no source file information for ~s~@[ with specializers ~s~]~@[ qualifers ~s~]."
- name classes qualifiers))))
-
- (defun get-source-files-with-types&classes (sym &optional (type t) classes qualifiers the-method)
- (labels
- ((merge-types (l)
- (let ((ftype (car l)))
- (cond
- ((eq ftype 'setf)
- (mapcan #'merge-types (cdr l)))
- ((or (eq type t)(eq ftype type))
- (let* ((foo #'(lambda (x)
- (when x
- ; if x is consp it's (<method> file file ..)
- (cond
- ((consp x)
- (when (or (not (or classes qualifiers))
- (if the-method
- (methods-match-p (car x) the-method)
- (source-files-like-em classes qualifiers
- (car x))))
- (merge-class x)))
- (t (list (cons ftype x))))))))
- (declare (dynamic-extent foo))
- (mapcan foo (if (consp (cdr l)) (cdr l)(list (cdr l)))))))))
- (merge-class (l)
- (if (consp (cdr l))
- (mapcan
- #'(lambda (x)
- (when x (list (cons (car l) x))))
- (cdr l))
- (list l))))
- (declare (dynamic-extent #'merge-types))
- (let (files)
- (when (and (not the-method)(eq type 'method))
- (let ((methods (find-applicable-methods sym classes qualifiers)))
- (when methods
- (setq files (mapcan
- #'(lambda (m)
- (edit-definition-p m))
- methods)))))
- (if files files
- (let (setf-p result)
- (if (and (consp sym)(eq (car sym) 'setf))
- (setq sym (cadr sym) setf-p t))
- (setq result (%source-files sym))
- (if (not (consp result))
- (setq result
- (if (not setf-p)
- (if (or (eq type t)(eq type 'function))
- `((function . ,result)))))
- (if setf-p (setq result (list (assq 'setf result)))))
- (mapcan #'merge-types result))))))
-
- ; we need this because callers can find a method which is not the current def
- ; (i.e. its really garbage)
- ; why don't we get the right one instead - then we can use eq again??
- ; Oh well leave it just in case record source file gets confused.
- (defun methods-match-p (x y)
- (or (eq x y)
- (and (typep x 'method)
- (typep y 'method)
- (equal (method-name x)
- (method-name y))
- ; this is not right for eql methods with non-constant frobs
- (equal (method-specializers x)
- (method-specializers y))
- (equal (method-qualifiers x)
- (method-qualifiers y)))))
-
- (defun edit-definition-p (name &optional (type t) &aux specializers qualifiers the-method)
- (when (consp name)
- (multiple-value-setq (type name specializers qualifiers)
- (parse-definition-spec name)))
- (when (and specializers (consp specializers)) (setq type 'method))
- (typecase name
- (method
- (setq qualifiers (%method-qualifiers name)
- specializers (mapcar #'(lambda (s)
- (if (consp s) s (class-name s)))
- (%method-specializers name))
- the-method name
- name (%method-name name)
- type 'method))
- (function
- (return-from edit-definition-p
- (edit-definition-p (function-name name) type))))
- (let (files str newname)
- (setq files (or (get-source-files-with-types&classes name type specializers qualifiers the-method)
- (and
- (not the-method)
- (symbolp name)
- (or (and
- (setq str (symbol-name name))
- (memq (schar str (1- (length str))) '(#\. #\, #\:))
- (setq newname
- (find-symbol (%substr str 0 (1- (length str)))
- (symbol-package name)))
- (get-source-files-with-types&classes newname type specializers qualifiers))
- (let ((syms (find-all-symbols name)))
- (do ((lst syms (cdr lst))
- (val nil))
- ((null lst) nil)
- (when (and (neq (car lst) name)
- (setq val
- (get-source-files-with-types&classes
- (car lst) type specializers qualifiers)))
- (setq newname (car lst))
- (return val))))))))
- (multiple-value-bind (ipath itype) (interface-definition-p name type)
- (when (and ipath (not (member (pathname-name ipath) files
- :key #'(lambda (x) (pathname-name (cdr x))) :test 'equal)))
- (push (cons itype ipath) files)))
- (when (and files newname) (setq name newname))
- (values files name type specializers qualifiers)))
-
-
- (defun format-definition-pathnames (object &optional (stream t))
- (let ((thing (car object))
- (path (cdr object))
- (fstr "<~s ~s>"))
- (if (typep thing 'standard-method)
- (progn
- (if (and *ed-show-setf* (consp (method-name thing)))
- (setq fstr"<SETF ~s ~s>"))
- (let ((qualifiers (%method-qualifiers thing)))
- (format stream fstr (case (length qualifiers)
- (0 :primary)
- (1 (car qualifiers))
- (t qualifiers))
- (mapcar #'(lambda (class)
- (if (consp class)
- class
- (or (class-name class) class)))
- (%method-specializers thing)))))
- (format stream "~s" thing))
- (when (or (stringp path) (pathnamep path))
- (format stream " ~s" (pathname-to-window-title path)))))
-
- (defun edit-definition (name &optional (type t))
- (multiple-value-bind (files name type classes qualifiers)
- (edit-definition-p name type)
- (declare (ignore-if-unused type))
- (if (not files)
- (values nil nil name type classes qualifiers)
- (cond ((null (cdr files))
- (let ((pos (edit-definition-2 (car files) name)))
- (values pos files name type classes qualifiers)))
- (t
- (let* ((ed-show-setf
- (dolist (f files)
- (let ((thing (car f)))
- (when (and (typep thing 'method)
- (consp (setq thing (method-name thing)))
- (not (equal thing name)))
- (return t)))))
- w)
- (setq w
- (select-item-from-list
- (if classes ; already sorted by applicability (true always?)
- files
- (setq files (sort files #'edit-definition-spec-lessp :key #'car)))
- :table-print-function #'(lambda (a &optional (b t))
- (let ((*ed-show-setf* ed-show-setf))
- (format-definition-pathnames a b)))
- :window-title
- (format nil "Definitions of ~S." name)
- :modeless t
- :default-button-text "Find it"
- :action-function
- #'(lambda (list)
- (if (option-key-p) (window-close w))
- (edit-definition-2 (car list) name))))
- (values t files name type classes qualifiers)))))))
-
- (defun edit-definition-2 (pathname name)
- ; pathname isn't. Car is 'variable, a method, 'function, 'class etc.
- ; Cdr is the pathname. - only called if source file info
- (let (type pos new-window classes qualifiers)
- (when pathname
- (setq type (car pathname)
- pathname (or (cdr pathname) "New"))
- (typecase type
- (method
- (setq qualifiers (%method-qualifiers type)
- classes (mapcar #'(lambda (s)
- (if (consp s) s (class-name s)))
- (%method-specializers type))
- name (%method-name type)
- type 'method)))
- (setq new-window
- (or (pathname-to-window pathname)
- (and (stringp pathname)
- ; does it look like a real pathname ?
- (equalp pathname "New")
- ; No, pick a random fred window that has no pathname
- (my-string-to-window pathname))))
- (if new-window
- (window-select new-window)
- (setq new-window (ed pathname)))
- (let ((buf (fred-buffer new-window)))
- (setq pos (or (search-for-def buf name type classes qualifiers)
- ; ? do we really want to do this ?
- (search-for-def-dumb buf name type classes qualifiers
- 0 (buffer-size buf) T)))) ; and dumber
- (when pos
- (ed-push-mark new-window)
- (window-scroll new-window pos)))
- (when (not pos)(edit-definition-error name classes qualifiers pathname))
- (values pos pathname)))
-
- ; slight tweak to make it applicable for edit callers
- (defun edit-definition-spec-lessp (x y)
- (cond ((symbolp x)
- (if (symbolp y) (string-lessp x y) t))
- ((symbolp y) nil)
- ((typep x 'standard-method)
- (if (typep y 'standard-method)
- (let ((y-name (method-name y))
- (x-name (method-name x)))
- (if (not (equal x-name y-name))
- (progn
- (if (consp x-name)(setq x-name (format nil "~A" x-name)))
- (if (consp y-name)(setq y-name (format nil "~A" y-name)))
- (string-lessp x-name y-name))
- (let ((y-specs (method-specializers y))
- y-spec)
- (dolist (x-spec (method-specializers x)
- (or y-specs
- (let ((y-qs (method-qualifiers y))
- y-q)
- (dolist (x-q (method-qualifiers x) y-qs)
- (unless y-qs (return nil))
- (setq y-q (pop y-qs))
- (cond ((string-lessp x-q y-q)
- (return t))
- ((string-lessp y-q x-q)
- (return nil)))))))
- (unless y-specs (return nil))
- (setq y-spec (pop y-specs))
- (if (typep x-spec 'class)
- (if (typep y-spec 'class)
- (let ((x-name (class-name x-spec))
- (y-name (class-name y-spec)))
- (if (edit-definition-spec-lessp x-name y-name)
- (return t))
- (if (edit-definition-spec-lessp y-name x-name)
- (return nil)))
- (return nil))
- t)))))
- t))
- ((typep y 'standard-method) nil)
- (t (< (%address-of x) (%address-of y)))))
-
- (defun search-for-def-dumb (w target type classes qualifiers pos end &optional dumber)
- (when (null (stringp target))
- (setq target (if (symbolp target) (symbol-name target)(format nil "~A" target)))
- (when (eq type 'structure)(setq target (%str-cat "(" target))))
- (let ((target-length (length target))
- result)
- (while (and pos (< pos end))
- (setq pos (buffer-forward-search w "(def" pos end))
- (when pos
- (let* ((defstart (- pos 4))
- (after-d-e-f pos)
- (defend (buffer-fwd-symbol w (1- after-d-e-f) end)))
- (setq pos (buffer-skip-fwd-wsp&comments w defend end))
- (when (and (setq pos (buffer-delimited-substring-p w target pos end target-length))
- (or (= defstart 0)
- ; at least avoid finding (let ((def (blah))))
- (memq (buffer-char w (1- defstart)) '(#\newline #\space)))
- (or (neq type 'method)
- (search-method-classes w classes qualifiers pos end)))
- (setq result defstart))
- (setq pos defend))))
- (or result (when dumber
- (setq result 0)
- (while (setq result (buffer-forward-search w target result end))
- (when (%str-member (buffer-char w result) symbol-specials)
- (return-from search-for-def-dumb (- result target-length))))))))
-
- ; from ccl-menus
- (defun edit-definition-dialog (&aux (initial-string %edit-definition-string))
- (let ((w (front-window)))
- (when (and w (typep w 'fred-window))
- (multiple-value-bind (b e)(selection-range w)
- (when (neq b e)(setq %edit-definition-string (buffer-substring (fred-buffer w) b e))))))
- (if (and *edit-definition-dialog*
- (wptr *edit-definition-dialog*))
- (window-select *edit-definition-dialog*)
- (setq *edit-definition-dialog*
- (get-string-from-user
- "Enter the name of a symbol. The definition (if there is one) will be found, or a list of choices will be shown."
- :window-title "Edit Definition"
- :initial-string initial-string
- :modeless t
- :action-function
- #'(lambda (new-string)
- (let (sym)
- (unless (equal new-string "")
- (setq sym (read-from-string new-string))
- (edit-definition-spec sym)
- (setq %edit-definition-string new-string))))))))
-
- )